14.2 Die Metadaten mittels Reflexion abfragen  
14.2.1 Was ist Reflexion?  
Nachdem Sie nun die wichtigsten Gesichtspunkte einer Assembly kennen gelernt haben, wenden wir uns einem eng verwandten Thema zu: der Reflexion. Dabei handelt es sich um einen Prozess, der den Zugriff auf die Metadaten einer Assemblierung ermöglicht. Sie können damit zur Laufzeit Typinformationen abfragen. Die Reflexion ermöglicht die Analyse von Klassen, Strukturen, Schnittstellen usw. Das ist aber noch nicht alles. Sie können mit der Reflexion sogar Methoden dynamisch aufrufen und im Extremfall sogar zur Laufzeit MSIL-Code generieren.
Die in Zusammenhang mit der Reflexion stehenden Klassen befinden sich im Namespace System.Reflection. Dahinter verstecken sich ungezählte Methoden, welche die Auswertung einer Assemblierung und ihrer Metadaten ermöglichen. Daher ist es unmöglich, hier auf alle Features einzugehen. Dennoch möchte ich Ihnen einige Möglichkeiten vorstellen, welche die Reflexion bietet. Sollten Sie weitergehende Informationen benötigen, lesen Sie bitte in der .NET-Dokumentation nach.
14.2.2 Der Mittelpunkt der Reflexion: die Klasse »Type«  
Müsste man die wichtigste Klasse der Reflexion nennen, es wäre ohne Zweifel Type. Sie ist im Namespace System beheimatet und beschreibt gewissermaßen die Eingangstür zur Reflexion und stellt die wichtigsten Hilfsmittel für den Zugriff auf die Metadaten zur Verfügung. Die Methoden ermöglichen die Abfrage von Typinformationen, zu denen Konstruktoren, Methoden, Ereignisse, Felder und Eigenschaften eines bestimmten Typs gehören.
Um einen bestimmten Typ untersuchen zu können, benötigen wir einen Verweis auf das einem Typ zugeordnete Type-Objekt. Hier bieten sich zwei Möglichkeiten an:
|
Ihnen liegt eine konkrete Objektreferenz vor, die Sie untersuchen wollen. Rufen Sie in diesem Fall auf die Objektvariable die von Object geerbte Methode GetType auf. |
|
Sie möchten, ohne die Existenz eines konkreten Objekts in den Händen zu halten, einen Typ untersuchen. Rufen Sie hierzu die statische Methode GetType der Klasse Type auf. |
|
Die zur Verfügung stehenden Varianten wollen wir uns nun im Programmcode ansehen. |
Ermittlung von »Type« anhand eines konkreten Objekts
Zu den Methoden, die jede Klasse von Object erbt, gehört die Instanzmethode GetType. Ihr Aufruf auf eine Objektreferenz liefert ein Objekt vom Typ Type zurück, dessen Eigenschaften und Methoden eine genaue Untersuchung des zugrunde liegenden Datentypen ermöglichen.
Stellen wir uns vor, wir wollten wissen, welche Methoden von der Klasse Program veröffentlicht werden. Auf eine Type-Referenz brauchen wir dann nur die Methode GetMethods aufzurufen, die ein Array vom Typ MethodInfo zurückliefert.
| Public Function GetMethods() As MethodInfo()
|
MethodInfo ermöglicht den Zugriff auf die Metadaten der Methode und ermittelt die Attribute einer Methode. Über die Eigenschaften und Methoden können Sie feststellen, ob die Methode statisch oder abstrakt ist, welche Parameter sie definiert usw.
Das folgende Codefragment enthält in der Klasse Program nicht nur die Startmethode Main, sondern aus Anschauungsgründen noch eine zusätzliche benutzerdefinierte Methode.
| Imports System.Reflection
|
| Class Program
|
| Public Shared Sub Main()
|
| Dim prgm As New Program
|
| Dim typ As Type = prgm.GetType()
|
| Dim info() As MethodInfo = typ.GetMethods()
|
| Dim temp As MethodInfo
|
| For Each temp In info
|
| Console.WriteLine(temp.Name)
|
| Next
|
| Console.ReadLine()
|
| End Sub
|
| Public Sub MyMethod()
|
| ' Anweisungen
|
| End Sub
|
| End Class
|
Innerhalb einer For Each-Schleife greifen wir auf jedes MethodInfo-Objekt zu und rufen dessen Eigenschaft Name ab, die uns den Methodenbezeichner zurückliefert. Wenn Sie das Programm starten, erkennen Sie, dass alle öffentlichen Methoden erfasst werden, auch die von der oder den Basisklassen geerbten. Um auch die gegebenenfalls Private deklarierten Methoden zu sehen, müssen Sie die Überladung von GetMethods aufrufen und dem Parameter eine Konstante der Enumeration BindingFlags übergeben. Über die verschiedenen Member dieser Enumeration können Sie auch weiteren Einfluss auf die Rückgabe von GetMethods ausüben.
Ermittlung von »Type« anhand des Typs
Darüber hinaus können Sie auch die GetType-Methode der Klasse Type aufrufen und übergeben dabei den gewünschten Typ als Argument in einer Zeichenfolge. GetType ist mehrfach überladen.
| Public Shared Function GetType(name As String) As Type
|
| Public Shared Function GetType(name As String, _
|
| throwOnError As Boolean) As Type
|
| Public Shared Function GetType(name As String, _
|
| throwOnError As Boolean, ignoreCase As Boolean) As Type
|
Dem ersten Parameter wird in allen Fällen der vollständig qualifizierende Name des gewünschten Typs übergeben. Der zweite Parameter kann die Laufzeit anweisen, eine Exception auszulösen, falls der im ersten Parameter genannte Typ nicht gefunden wird. Der dritte Parameter schließlich gibt an, ob bei der Typsuche zwischen der Groß- und Kleinschreibung unterschieden werden soll.
| Dim typ As Type = Type.GetType("ConsoleApplication.Program")
|
| Dim info() As MethodInfo = typ.GetMethods()
|
| ...
|
Untersuchung eines Typen
Die Klasse Type ermöglicht Ihnen, einen bestimmten Typ in praktisch jeder Hinsicht zu analysieren. Sie können ermitteln, ob es sich um eine Klassendefinition, eine Schnittstelle, eine Struktur usw. handelt, Sie können feststellen, ob der Typ abstrakt ist, öffentlich oder privat.
Damit Sie ein Gefühl dafür bekommen, welche Unterstützung Sie erwarten können, sollten Sie sich das folgende Beispielprogramm einmal ansehen. Es zeigt nur einen kleinen Ausschnitt der Möglichkeiten, einen Typ zu untersuchen. Als Grundlage wird dabei wieder auf unsere Klasse Circle zurückgegriffen, die wir in den Kapiteln 4 bis 6 kontinuierlich entwickelt hatten.
| ' ---------------------------------------------------------
|
| ' Beispiel: ...\Kapitel 14\GetTypeInformationDemo
|
| ' ---------------------------------------------------------
|
| Imports System.Reflection
|
| Module Module1
|
| Sub Main()
|
| Dim typ As Type = _
|
| Type.GetType("GetTypeInformationDemo.Circle")
|
| Console.WriteLine("Typuntersuchung:")
|
| Console.WriteLine(New String("="c, 40))
|
| If (typ.IsClass) Then
|
| Console.WriteLine("{0} ist eine Klasse.", typ.Name)
|
| ElseIf (typ.IsInterface) Then
|
| Console.WriteLine("{0} ist eine Klasse.", typ.Name)
|
| ElseIf (typ.IsArray) Then
|
| Console.WriteLine("{0} ist eine Klasse.", typ.Name)
|
| ElseIf (typ.IsEnum) Then
|
| Console.WriteLine("{0} ist eine Klasse.", typ.Name)
|
| End If
|
| Console.WriteLine()
|
| Console.WriteLine("----- Zugriffsmodifizierer -----")
|
| Console.WriteLine("Public = {0}", typ.IsPublic)
|
| Console.WriteLine("Private = {0}", typ.IsNotPublic)
|
| Console.WriteLine("NotInheritable = {0}", typ.IsSealed)
|
| Console.WriteLine("MustInherit = {0}", typ.IsAbstract)
|
| Console.WriteLine()
|
| Console.WriteLine("----- Ereignisse -----")
|
| Dim tempEI As EventInfo
|
| For Each tempEI In typ.GetEvents()
|
| Console.Write("Name = {0} : ", tempEI.Name)
|
| Console.WriteLine(tempEI.EventHandlerType)
|
| Next
|
| Console.WriteLine()
|
| Console.WriteLine("----- Öffentliche Felder -----")
|
| Dim tempFI As FieldInfo
|
| For Each tempFI In typ.GetFields()
|
| Console.Write("Name = {0} : ", tempFI.Name)
|
| Console.WriteLine(tempFI.FieldType)
|
| Next
|
| Console.WriteLine()
|
| Console.WriteLine("----- Methoden -----")
|
| Dim tempMI As MethodInfo
|
| For Each tempMI In typ.GetMethods()
|
| Console.Write("Name = {0} (", tempMI.Name)
|
| Dim para As ParameterInfo
|
| For Each para In tempMI.GetParameters()
|
| Console.Write("{0} ", para.ParameterType)
|
| Next
|
| Console.WriteLine(")")
|
| Next
|
| Console.ReadLine()
|
| End Sub
|
| End Module
|
Der Code beschränkt sich darauf, nur öffentliche Member von Circle auszugeben. Hierbei handelt es sich, nach einer zuvor durchgeführten allgemeinen Untersuchung von Circle, um Ereignisse, Felder und Methoden. Von den Methoden werden zudem die Typen der Parameter, so vorhanden, abgefragt, die Ereignisse und Felder geben Auskunft darüber, von welchem Typ sie sind. Beachten Sie, dass die Klassen MethodInfo, FieldInfo, EventInfo und ParameterInfo, die in diesem Beispiel auftreten, weitergehende Informationen bereitstellen.
Die Ausgabe an der Konsole zeigt die Abbildung 14.13.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 14.13 Die Ausgabe des Beispielprogramms »GetTypeInformationDemo«
|